﻿using System;
using Faml;
using Faml.Frontend;
using Faml.Optimization;
using System.Reflection;
using System.IO;
using System.Collections.Generic;

public class FamlRunnerApp
{
    private static RuntimeEnvironment runtime;
    private static List<ExternalCommand> commands = new List<ExternalCommand>();

    public static void Main(string[] args)
    {
        const string Title = "Faml Command Line";
        const string Version = "Version 1.0 beta";
        const string Copyright = "(C) GC RAS & MSU CMC";
        Console.WriteLine("{0} {1} {2}.", Title, Version, Copyright);

        runtime = new RuntimeEnvironment();
        Console.WriteLine("{0} operation(s) found in {1} assembly(ies)", runtime.OperationCount, runtime.AssemblyCount);

        commands.Add(new WriteCommand());
        commands.Add(new TextFileCommand());
        commands.Add(new NetCDFCommand());

        foreach (string arg in args)
            ProcessArg(arg);
    }

    private static void ProcessArg(string arg)
    {
        if (arg.StartsWith("/d"))
            ProcessDefine(arg.Substring(2));
        else
            ProcessFile(arg);
    }

    private static void ProcessDefine(string def)
    {
        try
        {
            Parser mp = new Parser(def);
            mp.MoveNext();
            FamlDefinition md = runtime.Compiler.ParseDefinition(mp);
            Console.WriteLine("Symbol {0} is defined as {1}.", md.Name, md.Body.ToString());
        }
        catch
        {
            int ep = def.IndexOf('=');
            if (ep < 1)
                Console.WriteLine("Syntax error in command line arg /d{0}.", def);
            else
            {
                string name = def.Substring(0, ep);
                string val = def.Substring(ep + 1);
                runtime.Context.AddDefinition(new FamlDefinition(name, new FamlConstant<string>(val)));
                Console.WriteLine("Symbol {0} is defined as {1}.", name, val);
            }
        }
    }

    private static void ProcessFile(string path)
    {
        Console.Write("Loading {0} . . . ",path);
        try
        {
            StreamReader sr = new StreamReader(path);
            Parser parser = new Parser(sr);
            parser.MoveNext();
            Console.WriteLine("done.");
            while (true)
            {
                if (parser.MatchKeyword("def"))
                {
                    parser.MoveNext();
                    runtime.Compiler.ParseDefinition(parser);
                }
                else if (parser.TokenType == TokenType.Ident)
                {
                    ExternalCommand cmd = commands.Find(c => c.Name == parser.TokenText);
                    if (cmd == null)
                        throw new Exception("Unknown command " + parser.TokenText);
                    parser.MoveNext();
                    cmd.Parse(parser, runtime);
                }
                else if (parser.TokenType == TokenType.Eof)
                    break;
                else
                   throw new Exception("Syntax error");
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("file not found!");
        }
    }


}